home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: AddHTActions.c
- //
- // Contains: Sample code for adding hypertext links to a QuickTime movie with a text track.
- //
- // Written by: Tim Monroe
- // Based on existing code by Bill Wright
- //
- // Copyright: © 1999 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <1> 07/19/99 rtm first file from bw; revised to sample code coding style;
- // added Endian macros and other niceties for cross-platform
- // support; works fine on Windows and MacOS
- //
- // This file contains some sample code that adds a few wired actions to a movie that has a
- // text track. In particular, it adds two go-to-URL actions to parts of the text track.
- //
- // A text media sample is a 16-bit length word followed by the text of that sample. Optionally,
- // one or more atoms of additional data (called text atom extensions) may follow the text in the
- // sample. The length word specifies the total number of bytes in the text and in any text atom
- // extensions that follow the text. These text atom extensions are organized as "classic" atom
- // structures: a 32-bit length field, followed by a 32-bit type field, followed by the data in
- // the atom. Here, the length field specifies the total length of the atom (that is, 8 plus the
- // number of bytes in the data.) All the data in the text extension atom must be in big-endian
- // format.
- //
- // To add hypertext actions to a text sample, you simply add a text atom extension of the type
- // kHyperTextTextAtomType to the end of the sample; the data of the text atom extension is the
- // container that holds the information about the actions. So our task boils down to this: find
- // a text sample, create an atom container holding information about the desired actions, and then
- // append a text extension atom whose data is that atom container to the end of the text sample.
- // Then replace the previous text sample with the new one in the text track.
- //
- // For complete information about wired actions, see the chapter "Wired Sprites" in the book
- // Programming With QuickTime Sprites.
- //
- //////////
-
- #include "AddHTActions.h"
-
-
- //////////
- //
- // main/WinMain
- // The main function for this application.
- //
- //////////
-
- #if TARGET_OS_MAC
- void main (void)
- #elif TARGET_OS_WIN32
- int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR theCmdLine, int nCmdShow)
- #endif
- {
- OSType myTypeList[1] = {MovieFileType};
- StandardFileReply myReply;
- Str255 myPrompt = "\pSample Hypertext Movie Name:";
- Str255 myDefaultName = "\pUntitled.mov";
- OSErr myErr = noErr;
-
- #if TARGET_OS_WIN32
- InitializeQTML(0L); // initialize QuickTime Media Layer
- #endif
-
- #if TARGET_OS_MAC
- MaxApplZone(); // init everything
- InitGraf(&qd.thePort);
- InitFonts();
- FlushEvents(everyEvent, 0);
- InitWindows();
- InitMenus();
- InitDialogs(NULL);
- TEInit();
- InitCursor();
- #endif
-
- myErr = EnterMovies();
- if (myErr != noErr)
- goto bail;
-
- // elicit a file from the user to save the new movie into
- StandardPutFile(myPrompt, myDefaultName, &myReply);
-
- // create a text movie with hypertext links
- if (myReply.sfGood) {
- myErr = AddHTAct_CreateTextMovie(&myReply.sfFile);
- if (myErr == noErr)
- myErr = AddHTAct_AddHyperTextToTextMovie(&myReply.sfFile);
- }
-
- bail:
- ExitMovies();
-
- #if TARGET_OS_WIN32
- // terminate the QuickTime Media Layer
- TerminateQTML();
- return(1);
- #endif
-
- #if TARGET_OS_MAC
- return;
- #endif
- }
-
-
- //////////
- //
- // AddHTAct_CreateTextMovie
- // Create a movie with a text track.
- //
- //////////
-
- static OSErr AddHTAct_CreateTextMovie (FSSpec *theFSSpec)
- {
- short myResRefNum = -1;
- short myResID = movieInDataForkResID;
- Movie myMovie = NULL;
- Track myTrack = NULL;
- Media myMedia = NULL;
- MediaHandler myHandler = NULL;
- Rect myTextBox;
- RGBColor myTextColor = {0x6666, 0xCCCC, 0xCCCC};
- RGBColor myBackColor = {0x3333, 0x6666, 0x6666};
- RGBColor myHiliteColor = {0x0000, 0x0000, 0x0000};
- long myDisplayFlags = 0;
- short myHiliteStart = 0;
- short myHiliteEnd = 0;
- TimeValue myNewMediaTime;
- TimeValue myScrollDelay = 0;
- #if TARGET_OS_MAC
- char myText[] = "\rPlease take me to Apple or CNN";
- #else
- char myText[] = "\nPlease take me to Apple or CNN";
- #endif
- long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile | newMovieActive;
- OSErr myErr = noErr;
-
- //////////
- //
- // create a new text movie
- //
- //////////
-
- myErr = CreateMovieFile(theFSSpec, FOUR_CHAR_CODE('TVOD'), 0, myFlags, &myResRefNum, &myMovie);
- if (myErr != noErr)
- goto bail;
-
- myTrack = NewMovieTrack(myMovie, FixRatio(kWidth320, 1), FixRatio(kHeight240, 1), kTrackVolumeZero);
- myMedia = NewTrackMedia(myTrack, TextMediaType, kTimeScale600, NULL, 0);
- if ((myTrack == NULL) || (myMedia == NULL))
- goto bail;
-
- myErr = BeginMediaEdits(myMedia);
- if (myErr != noErr)
- goto bail;
-
- myHandler = GetMediaHandler(myMedia);
- if (myHandler == NULL)
- goto bail;
-
- //////////
- //
- // add a text sample to the movie
- //
- //////////
-
- MacSetRect(&myTextBox, 0, 0, kWidth320, kHeight240);
- MacInsetRect(&myTextBox, kTextBoxInset, kTextBoxInset);
-
- myErr = (OSErr)TextMediaAddTextSample( myHandler,
- myText,
- strlen(myText),
- kFontIDSymbol,
- kSize48,
- kFacePlain,
- &myTextColor,
- &myBackColor,
- teCenter,
- &myTextBox,
- myDisplayFlags,
- myScrollDelay,
- myHiliteStart,
- myHiliteEnd,
- &myHiliteColor,
- kTimeScale600,
- &myNewMediaTime);
- if (myErr != noErr)
- goto bail;
-
- myErr = EndMediaEdits(myMedia);
- if (myErr != noErr)
- goto bail;
-
- // add the media to the track, at time 0
- myErr = InsertMediaIntoTrack(myTrack, kTrackStartTimeZero, myNewMediaTime, kTimeScale600, fixed1);
- if (myErr != noErr)
- goto bail;
-
- // add the movie resource
- myErr = AddMovieResource(myMovie, myResRefNum, &myResID, NULL);
- if (myErr != noErr)
- goto bail;
-
- bail:
- if (myResRefNum != -1)
- CloseMovieFile(myResRefNum);
-
- if (myMovie != NULL)
- DisposeMovie(myMovie);
-
- return(myErr);
- }
-
-
- //////////
- //
- // AddHTAct_CreateHyperTextActionContainer
- // Return, through the theActions parameter, an atom container that contains some hypertext actions.
- //
- //////////
-
- static OSErr AddHTAct_CreateHyperTextActionContainer (QTAtomContainer *theActions)
- {
- QTAtom myEventAtom = 0;
- QTAtom myActionAtom = 0;
- QTAtom myHyperTextAtom = 0;
- QTAtom myWiredObjectsAtom = 0;
- long myAction;
- long mySelStart1 = 19;
- long mySelEnd1 = 24;
- long mySelStart2 = 28;
- long mySelEnd2 = 31;
- long myValue;
- char myAppleURL[64] = "\pwww.apple.com\0";
- char myCnnURL[64] = "\pwww.cnn.com\0";
- OSErr myErr = noErr;
-
- myErr = QTNewAtomContainer(theActions);
- if (myErr != noErr)
- goto bail;
-
- // create a wired objects atom
- myErr = QTInsertChild(*theActions, kParentAtomIsContainer, kTextWiredObjectsAtomType, kIndexOne, kIndexZero, kZeroDataLength, NULL, &myWiredObjectsAtom);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // add a hypertext link to the wired objects atom: ID 1
- //
- //////////
-
- myErr = QTInsertChild(*theActions, myWiredObjectsAtom, kHyperTextItemAtomType, kIDOne, kIndexZero, kZeroDataLength, NULL, &myHyperTextAtom);
- if (myErr != noErr)
- goto bail;
-
- myValue = EndianS32_NtoB(mySelStart1);
- myErr = QTInsertChild(*theActions, myHyperTextAtom, kRangeStart, kIDOne, kIndexZero, sizeof(long), &myValue, NULL);
- if (myErr != noErr)
- goto bail;
-
- myValue = EndianS32_NtoB(mySelEnd1);
- myErr = QTInsertChild(*theActions, myHyperTextAtom, kRangeEnd, kIDOne, kIndexZero, sizeof(long), &myValue, NULL);
- if (myErr != noErr)
- goto bail;
-
- // add an event atom to the hypertext atom;
- // the event type can be any of the five mouse events: down, up, trigger, enter, exit
- myErr = QTInsertChild(*theActions, myHyperTextAtom, kQTEventType, kQTEventMouseClick, kIndexZero, kZeroDataLength, NULL, &myEventAtom);
- if (myErr != noErr)
- goto bail;
-
- myErr = QTInsertChild(*theActions, myEventAtom, kAction, kIndexOne, kIndexOne, kZeroDataLength, NULL, &myActionAtom);
- if (myErr != noErr)
- goto bail;
-
- myAction = EndianS32_NtoB(kActionGoToURL);
- myErr = QTInsertChild(*theActions, myActionAtom, kWhichAction, kIndexOne, kIndexOne, sizeof(long), &myAction, NULL);
- if (myErr != noErr)
- goto bail;
-
- myErr = QTInsertChild(*theActions, myActionAtom, kActionParameter, kIndexOne, kIndexOne, myAppleURL[0] + 1, &myAppleURL[1], NULL);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // add a hypertext link to the wired objects atom: ID 2
- //
- //////////
-
- myErr = QTInsertChild(*theActions, myWiredObjectsAtom, kHyperTextItemAtomType, kIDTwo, kIndexZero, kZeroDataLength, NULL, &myHyperTextAtom);
- if (myErr != noErr)
- goto bail;
-
- myValue = EndianS32_NtoB(mySelStart2);
- myErr = QTInsertChild(*theActions, myHyperTextAtom, kRangeStart, kIDOne, kIndexZero, sizeof(long), &myValue, NULL);
- if (myErr != noErr)
- goto bail;
-
- myValue = EndianS32_NtoB(mySelEnd2);
- myErr = QTInsertChild(*theActions, myHyperTextAtom, kRangeEnd, kIDOne, kIndexZero, sizeof(long), &myValue, NULL);
- if (myErr != noErr)
- goto bail;
-
- // add an event atom to the hypertext atom;
- // the event type can be any of the five mouse events: down, up, trigger, enter, exit
- myErr = QTInsertChild(*theActions, myHyperTextAtom, kQTEventType, kQTEventMouseClick, kIndexZero, kZeroDataLength, NULL, &myEventAtom);
- if (myErr != noErr)
- goto bail;
-
- myErr = QTInsertChild(*theActions, myEventAtom, kAction, kIndexOne, kIndexOne, kZeroDataLength, NULL, &myActionAtom);
- if (myErr != noErr)
- goto bail;
-
- myAction = EndianS32_NtoB(kActionGoToURL);
- myErr = QTInsertChild(*theActions, myActionAtom, kWhichAction, kIndexOne, kIndexOne, sizeof(long), &myAction, NULL);
- if (myErr != noErr)
- goto bail;
-
- myErr = QTInsertChild(*theActions, myActionAtom, kActionParameter, kIndexOne, kIndexOne, myCnnURL[0] + 1, &myCnnURL[1], NULL);
- if (myErr != noErr)
- goto bail;
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // AddHTAct_AddHyperActionsToSample
- // Add the specified atom container to the end of the specified media sample.
- //
- // Hypertext actions are stored at the end of the sample as a normal text atom extension.
- // In this case, the text atom type is kHyperTextTextAtomType and the data is the container data.
- //
- //////////
-
- static OSErr AddHTAct_AddHyperActionsToSample (Handle theSample, QTAtomContainer theActions)
- {
- Ptr myPtr = NULL;
- long myHandleLength;
- long myContainerLength;
- long myNewLength;
- OSErr myErr = noErr;
-
- myHandleLength = GetHandleSize(theSample);
- myContainerLength = GetHandleSize((Handle)theActions);
-
- myNewLength = (long)(sizeof(long) + sizeof(OSType) + myContainerLength);
-
- SetHandleSize(theSample, (myHandleLength + myNewLength));
- myErr = MemError();
- if (myErr != noErr)
- goto bail;
-
- HLock(theSample);
-
- // get a pointer to the beginning of the new block of space added to the sample
- // by the previous call to SetHandleSize; we need to format that space as a text
- // atom extension
- myPtr = *theSample + myHandleLength;
-
- // set the length of the text atom extension
- *(long *)myPtr = EndianS32_NtoB((long)(sizeof(long) + sizeof(OSType) + myContainerLength));
- myPtr += (sizeof(long));
-
- // set the type of the text atom extension
- *(OSType *)myPtr = EndianS32_NtoB(kHyperTextTextAtomType);
- myPtr += (sizeof(OSType));
-
- // set the data of the text atom extension;
- // we assume that this data is already in big-endian format
- HLock((Handle)theActions);
- BlockMove(*theActions, myPtr, myContainerLength);
-
- HUnlock((Handle)theActions);
- HUnlock(theSample);
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // AddHTAct_AddHyperTextToTextMovie
- // Add some hypertext actions to the specified text movie.
- //
- //////////
-
- static OSErr AddHTAct_AddHyperTextToTextMovie (FSSpec *theFSSpec)
- {
- short myResID = 0;
- short myResRefNum = -1;
- Movie myMovie = NULL;
- Track myTrack = NULL;
- Media myMedia = NULL;
- TimeValue myTrackOffset;
- TimeValue myMediaTime;
- TimeValue mySampleDuration;
- TimeValue mySelectionDuration;
- TimeValue myNewMediaTime;
- TextDescriptionHandle myTextDesc = NULL;
- Handle mySample = NULL;
- short mySampleFlags;
- Fixed myTrackEditRate;
- QTAtomContainer myActions = NULL;
- OSErr myErr = noErr;
-
- //////////
- //
- // open the movie file and get the first text track from the movie
- //
- //////////
-
- // open the movie file for reading and writing
- myErr = OpenMovieFile(theFSSpec, &myResRefNum, fsRdWrPerm);
- if (myErr != noErr)
- goto bail;
-
- myErr = NewMovieFromFile(&myMovie, myResRefNum, &myResID, NULL, newMovieActive, NULL);
- if (myErr != noErr)
- goto bail;
-
- // find first text track in the movie
- myTrack = GetMovieIndTrackType(myMovie, kIndexOne, TextMediaType, movieTrackMediaType);
- if (myTrack == NULL)
- goto bail;
-
- //////////
- //
- // get first media sample in the text track
- //
- //////////
-
- myMedia = GetTrackMedia(myTrack);
- if (myMedia == NULL)
- goto bail;
-
- myTrackOffset = GetTrackOffset(myTrack);
- myMediaTime = TrackTimeToMediaTime(myTrackOffset, myTrack);
-
- // allocate some storage to hold the sample description for the text track
- myTextDesc = (TextDescriptionHandle)NewHandle(4);
- if (myTextDesc == NULL)
- goto bail;
-
- mySample = NewHandle(0);
- if (mySample == NULL)
- goto bail;
-
- myErr = GetMediaSample(myMedia, mySample, 0, NULL, myMediaTime, NULL, &mySampleDuration, (SampleDescriptionHandle)myTextDesc, NULL, 1, NULL, &mySampleFlags);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // add hypertext actions to the first media sample
- //
- //////////
-
- // create an action container for hypertext actions
- myErr = AddHTAct_CreateHyperTextActionContainer(&myActions);
- if (myErr != noErr)
- goto bail;
-
- // add hypertext actions actions to sample
- myErr = AddHTAct_AddHyperActionsToSample(mySample, myActions);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // replace sample in media
- //
- //////////
-
- myTrackEditRate = GetTrackEditRate(myTrack, myTrackOffset);
- if (GetMoviesError() != noErr)
- goto bail;
-
- GetTrackNextInterestingTime(myTrack, nextTimeMediaSample | nextTimeEdgeOK, myTrackOffset, fixed1, NULL, &mySelectionDuration);
- if (GetMoviesError() != noErr)
- goto bail;
-
- myErr = DeleteTrackSegment(myTrack, myTrackOffset, mySelectionDuration);
- if (myErr != noErr)
- goto bail;
-
- myErr = BeginMediaEdits(myMedia);
- if (myErr != noErr)
- goto bail;
-
- myErr = AddMediaSample( myMedia,
- mySample,
- 0,
- GetHandleSize(mySample),
- mySampleDuration,
- (SampleDescriptionHandle)myTextDesc,
- 1,
- mySampleFlags,
- &myNewMediaTime);
- if (myErr != noErr)
- goto bail;
-
- myErr = EndMediaEdits(myMedia);
- if (myErr != noErr)
- goto bail;
-
- // add the media to the track
- myErr = InsertMediaIntoTrack(myTrack, myTrackOffset, myNewMediaTime, mySelectionDuration, myTrackEditRate);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // update the movie resource
- //
- //////////
-
- myErr = UpdateMovieResource(myMovie, myResRefNum, myResID, NULL);
- if (myErr != noErr)
- goto bail;
-
- // close the movie file
- myErr = CloseMovieFile(myResRefNum);
-
- bail:
- if (myActions != NULL)
- (void)QTDisposeAtomContainer(myActions);
-
- if (mySample != NULL)
- DisposeHandle(mySample);
-
- if (myTextDesc != NULL)
- DisposeHandle((Handle)myTextDesc);
-
- if (myMovie != NULL)
- DisposeMovie(myMovie);
-
- return(myErr);
- }